package com.yeskery.nut.cloud.feign;

import com.yeskery.nut.annotation.cloud.feign.FeignClient;
import com.yeskery.nut.bean.ApplicationContext;
import com.yeskery.nut.bean.NoSuchBeanException;
import com.yeskery.nut.core.Order;
import com.yeskery.nut.util.ReflectUtils;

import java.util.*;

/**
 * 基础feign请求处理器
 * @author sunjay
 * 2024/3/23
 */
public abstract class BaseFeignRequestHandler implements FeignRequestHandler {

    /** 拦截器链 */
    private final List<FeignRequestInterceptor> interceptors = new ArrayList<>();

    /** Feign客户端拦截器map */
    private final Map<FeignClient, List<FeignRequestInterceptor>> interceptorMap = new HashMap<>();

    /** 应用上下文 */
    private final ApplicationContext applicationContext;

    /** 是否更新拦截器链 */
    private volatile boolean updateInterceptors = false;

    /**
     * 构建基础feign请求处理器
     * @param applicationContext 应用上下文
     */
    protected BaseFeignRequestHandler(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public Object handle(FeignRequestMetadata feignRequestMetadata, FeignRequestData feignRequestData) {
        boolean refresh = false;
        if (!interceptors.isEmpty()) {
            if (updateInterceptors) {
                interceptors.sort(Comparator.comparing(Order::getOrder));
                updateInterceptors = false;
                refresh = true;
            }
        }
        for (FeignRequestInterceptor interceptor : getInterceptors(((FeignClientRequestData) feignRequestData).getFeignClient(), refresh)) {
            try {
                interceptor.process(feignRequestMetadata, feignRequestData);
            } catch (Exception e) {
                throw new FeignClientException("FeignRequestInterceptor [" + interceptor.getClass().getName() + "] Process Fail.", e);
            }
        }
        return doHandle(feignRequestMetadata, feignRequestData);
    }

    @Override
    public void addInterceptor(FeignRequestInterceptor feignRequestInterceptor) {
        if (feignRequestInterceptor == null) {
            throw new FeignClientException("FeignRequestInterceptor Must Not Be Null.");
        }
        interceptors.add(feignRequestInterceptor);
        updateInterceptors = true;
    }

    /**
     * 执行feign请求
     * @param feignRequestMetadata feign请求元数据
     * @param feignRequestData feign请求数据
     * @return 执行后的返回结果
     */
    protected abstract Object doHandle(FeignRequestMetadata feignRequestMetadata, FeignRequestData feignRequestData);

    /**
     * 获取应用上下文
     * @return 应用上下文
     */
    protected ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 获取拦截器链
     * @param feignClient feignClient客户端
     * @param refresh 是否刷新拦截器链
     * @return 拦截器链
     */
    private List<FeignRequestInterceptor> getInterceptors(FeignClient feignClient, boolean refresh) {
        List<FeignRequestInterceptor> feignRequestInterceptors = interceptorMap.get(feignClient);
        if (feignRequestInterceptors == null || refresh) {
            synchronized (this) {
                feignRequestInterceptors = new ArrayList<>(interceptors);
                for (Class<? extends FeignRequestInterceptor> clazz : feignClient.interceptors()) {
                    FeignRequestInterceptor interceptor;
                    try {
                        interceptor = applicationContext.getBean(clazz);
                    } catch (NoSuchBeanException e) {
                        interceptor = ReflectUtils.getNoConstructorTarget(clazz);
                    }
                    feignRequestInterceptors.add(interceptor);
                }
                if (!feignRequestInterceptors.isEmpty()) {
                    feignRequestInterceptors.sort(Comparator.comparing(Order::getOrder));
                }
                interceptorMap.put(feignClient, feignRequestInterceptors);
            }
        }
        return feignRequestInterceptors;
    }
}
